package com.ds.robot.assistant.service.yunxiao;

import com.alibaba.fastjson.JSON;
import com.aliyun.sdk.service.devops20210625.models.*;
import com.google.common.collect.Lists;
import com.ds.robot.assistant.enums.Env;
import com.ds.robot.assistant.enums.WorkItemCategoryEnum;
import com.ds.robot.assistant.model.YxBug;
import com.ds.robot.assistant.model.YxReq;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.PreDestroy;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * 作用： v1.0
 * <p>
 * <p>
 * GET /organization/{organizationId}/listProjects 获取项目列表
 *
 * @author WeiShaoying
 * 
 */
@Component
@Slf4j
@SuppressWarnings("ALL")
public class YunXiaoRequirementClient extends YunXiaoBase {


    @PreDestroy
    public void destroy() {
        log.info("云效需求Client准备关闭");
        asyncClient.close();
        log.info("云效需求Client关闭成功");
    }

    // HttpClient Configuration
        /*HttpClient httpClient = new ApacheAsyncHttpClientBuilder()
                .connectionTimeout(Duration.ofSeconds(10)) // Set the connection timeout time, the default is 10 seconds
                .responseTimeout(Duration.ofSeconds(10)) // Set the response timeout time, the default is 20 seconds
                .maxConnections(128) // Set the connection pool size
                .maxIdleTimeOut(Duration.ofSeconds(50)) // Set the connection pool timeout, the default is 30 seconds
                // Configure the proxy
                .proxy(new ProxyOptions(ProxyOptions.Type.HTTP, new InetSocketAddress("<your-proxy-hostname>", 9001))
                        .setCredentials("<your-proxy-username>", "<your-proxy-password>"))
                // If it is an https connection, you need to configure the certificate, or ignore the certificate(.ignoreSSL(true))
                .x509TrustManagers(new X509TrustManager[]{})
                .keyManagers(new KeyManager[]{})
                .ignoreSSL(false)
                .build();*/


    /**
     * 查询需求报告消息
     *
     * @return
     */
    public String queryRequirementMessage() throws Exception {
        long start = System.currentTimeMillis();

        StringBuilder message = new StringBuilder("# [长时间未启动需求跟踪报告]\n");
        StringBuilder content = new StringBuilder();
        List<CompletableFuture<ListWorkitemsResponse>> futureList = Lists.newArrayList();

        Map<String, String> projectMap = getProjectMap();
        for (Map.Entry<String, String> entry : projectMap.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            log.info("====开始处理：{}", value);
            ListWorkitemsRequest listWorkitemsRequest = ListWorkitemsRequest.builder()
                    .organizationId(ORGANIZATION_ID)
                    .spaceType("Project")
                    .spaceIdentifier(key)
                    .category(WorkItemCategoryEnum.Req.name())
                    .maxResults("200")
                    .conditions("{\"conditionGroups\":[[{\"fieldIdentifier\":\"status\",\"operator\":\"CONTAINS\",\"value\":[\"100005\",\"100010\",\"156603\"],\"toValue\":null,\"className\":\"status\",\"format\":\"list\"}]]}")
                    // Request-level configuration rewrite, can set Http request parameters, etc.
                    // .requestConfiguration(RequestConfiguration.create().setHttpHeaders(new HttpHeaders()))
                    .build();

            // Asynchronously get the return value of the API request
            CompletableFuture<ListWorkitemsResponse> response = asyncClient.listWorkitems(listWorkitemsRequest);
            futureList.add(response);
        }

        CompletableFuture<List<ListWorkitemsResponse>> allResultList = CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0]))
                .thenApply(v -> futureList.stream().map(CompletableFuture::join).filter(Objects::nonNull)
                        .collect(Collectors.toList()))
                .exceptionally(throwable -> {
                    throwable.printStackTrace();
                    return null;
                });
        List<ListWorkitemsResponse> responseList = allResultList.join();
        long totalReqCount = 0;
        if (!CollectionUtils.isEmpty(responseList)) {
            for (ListWorkitemsResponse response : responseList) {
                if (response.getBody() == null || CollectionUtils.isEmpty(response.getBody().getWorkitems())) {
                    continue;
                }

                String spaceIdentifier = response.getBody().getWorkitems().get(0).getSpaceIdentifier();
                Long totalCount = response.getBody().getTotalCount();

                if (totalCount != null && totalCount > 0) {

                    List<YxReq> reqList = response.getBody().getWorkitems().stream()
                            .map(workitems -> {
                                LocalDate createDate = Instant.ofEpochMilli(workitems.getGmtCreate()).atZone(ZoneId.systemDefault()).toLocalDate();
                                LocalDate today = LocalDate.now();
                                // int days = Period.between(createDate, today).getDays();
                                long between = ChronoUnit.DAYS.between(createDate, today);
                                String assignedTo = workitems.getAssignedTo();
                                String personName;
                                try {
                                    personName = userCache.get(assignedTo);
                                    // log.info("==== Req: 使用内存缓存查询姓名：{} 成功", personName);
                                } catch (Exception e) {
                                    personName = USER_MAP.getOrDefault(assignedTo, assignedTo);
                                }

                                return new YxReq(workitems.getIdentifier(), workitems.getSubject(),
                                        personName,
                                        FORMATTER.format(createDate), between);
                            })
                            //根据配置的阈值，过滤
                            .filter(req -> req.getDays() >= getDayThreshold())
                            .sorted(Comparator.comparing(YxReq::getDays).reversed())
                            .collect(Collectors.toList());

                    log.info("reqList = {}", JSON.toJSONString(reqList));

                    if (!CollectionUtils.isEmpty(reqList)) {
                        totalReqCount += reqList.size();

                        content.append("## <font color=\"info\">").append(projectMap.getOrDefault(spaceIdentifier, response.getBody().getWorkitems().get(0).getSpaceName())).append("</font>\n");
                        int k = 0;
                        for (YxReq yxReq : reqList) {
                            k++;
                            content.append(" > ").append(k).append(".").append(yxReq.getSubject()).append("<font color=\"warning\">**")
                                    .append(yxReq.getDays()).append("天**</font>[")
                                    .append(yxReq.getChargePerson()).append("]\n");
                        }
                        content.append("\n");
                        String reqUrl = String.format(REQ_FORMART, spaceIdentifier);

                        // String reqUrl = Optional.ofNullable(projectCache.get(spaceIdentifier)).map(ProjectInfoEntity::getReqUrl).orElse(null);
                        // if (!StringUtils.hasText(reqUrl)) {
                        //     log.warn("========ProjectCache没有命中reqUrl");
                        //     reqUrl = REQ_URL_MAP.getOrDefault(spaceIdentifier, "https://devops.aliyun.com/projex/project/889ea8b1980f95b17a579997e1/req");
                        // } else {
                        //     log.info("========ProjectCache命中reqUrl");
                        // }
                        content.append("[查看需求](").append(reqUrl).append(")");
                        content.append("\n\n");
                    }
                }
            }
        }

        message.append("**需求数量：<font color=\"warning\">").append(totalReqCount).append("个</font>**\n");

        long end = System.currentTimeMillis();
        log.info("====查询需求报告耗时：{}毫秒 ", (end - start));

        if (totalReqCount < 1) {
            message.append("\n\n").append("### Good Job !\n");
        } else {
            message.append(content);
        }
        message.append("\n <@wjn> <@liuchen_tqav> <@jianghaipeng_6g1v> <@lanhuimin_mkfr> <@limengqian_ft2b> <@所有人> \n请悉知~");
        return message.toString();
    }

    /**
     * 查询缺陷报告消息
     *
     * @return
     */
    @Deprecated
    public String queryBugMessage() {
        long start = System.currentTimeMillis();

        StringBuilder title = new StringBuilder("# [当前尚未解决缺陷跟踪报告]\n");
        StringBuilder content = new StringBuilder();
        List<CompletableFuture<ListWorkitemsResponse>> futureList = Lists.newArrayList();
        Map<String, String> projectMap = getProjectMap();
        for (Map.Entry<String, String> entry : projectMap.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            log.info("====开始处理：{}", value);
            ListWorkitemsRequest listWorkitemsRequest = ListWorkitemsRequest.builder()
                    .organizationId(ORGANIZATION_ID)
                    .spaceType("Project")
                    .spaceIdentifier(key)
                    .category(WorkItemCategoryEnum.Bug.name())
                    .maxResults("200")
                    .conditions("{\"conditionGroups\":[[{\"fieldIdentifier\":\"status\",\"operator\":\"CONTAINS\",\"value\":[\"30\",\"100005\",\"28\",\"100010\",\"32\",\"142838\"],\"toValue\":null,\"className\":\"status\",\"format\":\"list\"}]]}")
                    // Request-level configuration rewrite, can set Http request parameters, etc.
                    // .requestConfiguration(RequestConfiguration.create().setHttpHeaders(new HttpHeaders()))
                    .build();
            // Asynchronously get the return value of the API request
            CompletableFuture<ListWorkitemsResponse> response = asyncClient.listWorkitems(listWorkitemsRequest);
            futureList.add(response);
        }

        CompletableFuture<List<ListWorkitemsResponse>> allResultList = CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0]))
                .thenApply(v -> futureList.stream().map(CompletableFuture::join).filter(Objects::nonNull)
                        .collect(Collectors.toList()))
                .exceptionally(throwable -> {
                    throwable.printStackTrace();
                    return null;
                });
        List<ListWorkitemsResponse> responseList = allResultList.join();
        long totalBugCount = 0;

        // 遍历项目
        for (ListWorkitemsResponse response : responseList) {
            if (response.getBody() == null || CollectionUtils.isEmpty(response.getBody().getWorkitems())) {
                continue;
            }

            // Optional.flatMap 用于处理嵌套的Optional，避免多重空值检查，简化从嵌套结构中提取数据的过程。
            // List.stream().flatMap 用于处理流中的集合，将嵌套的集合扁平化为单一的流，方便后续的流操作。
            /*Optional<String> optional = Optional.ofNullable(response).map(ListWorkitemsResponse::getBody)
                    .map(ListWorkitemsResponseBody::getWorkitems)
                    .flatMap(list -> list.stream().findFirst()).map(ListWorkitemsResponseBody.Workitems::getSpaceIdentifier);
            */

            String spaceIdentifier = response.getBody().getWorkitems().get(0).getSpaceIdentifier();
            //当前项目下Bug数量
            Long count = response.getBody().getTotalCount();

            if (count != null && count > 0) {
                totalBugCount += count;

                content.append("## <font color=\"info\">").append(projectMap.getOrDefault(spaceIdentifier, response.getBody().getWorkitems().get(0).getSpaceName()))
                        .append("[").append(count).append("]</font>\n");

                List<String> idList = response.getBody().getWorkitems().stream().map(ListWorkitemsResponseBody.Workitems::getIdentifier).collect(Collectors.toList());
                log.info("{}: bugIdList = {}", response.getBody().getWorkitems().get(0).getSpaceName(), JSON.toJSONString(idList));
                List<GetWorkItemInfoResponse> workItemInfoResponseList = getGetWorkItemInfoResponse(idList);

                List<YxBug> bugList = workItemInfoResponseList.stream().map(GetWorkItemInfoResponse::getBody).map(GetWorkItemInfoResponseBody::getWorkitem)
                        .map(item -> new YxBug(item.getIdentifier(), item.getAssignedTo(), item.getStatus(),
                                Optional.ofNullable(item.getTagDetails()).flatMap(list -> list.stream().findFirst()).map(GetWorkItemInfoResponseBody.TagDetails::getName).orElse("")))
                        .collect(Collectors.toList());

                // 按照需求分组
                // mapFactory: 这是一个供应商（Supplier），用于创建一个用于收集结果的Map实例。通常情况下，你可以使用LinkedHashMap::new、HashMap::new或TreeMap::new等来指定Map的具体类型。
                // 这是因为groupingBy的结果是一个Map，mapFactory决定了这个Map的具体实现类，从而影响了分组结果的存储方式（例如，保持插入顺序、自然排序等）
                LinkedHashMap<String, LinkedHashMap<String, Map<String, Long>>> multGroupMap = bugList.stream().collect(Collectors.groupingBy(YxBug::getTagName, LinkedHashMap::new,
                        Collectors.groupingBy(YxBug::getChargePerson, LinkedHashMap::new,
                                Collectors.groupingBy(YxBug::getStatus, Collectors.counting())
                        )
                ));


                for (Map.Entry<String, LinkedHashMap<String, Map<String, Long>>> entry : multGroupMap.entrySet()) {
                    String tagName = entry.getKey();
                    if (!StringUtils.hasText(tagName)) {
                        tagName = TAG_EMPTY;
                    }
                    //计算需求的Bug数量之和
                    content.append("### 需求:").append(tagName).append("[").append(entry.getValue().values().stream().flatMapToLong(map -> map.values().stream().mapToLong(Long::longValue)).sum())
                            .append("]\n");
                    // 人员，缺陷数量
                    Map<String, Long> bugCountMap = new LinkedHashMap<>();
                    for (Map.Entry<String, Map<String, Long>> mapEntry : entry.getValue().entrySet()) {
                        String chargePerson = mapEntry.getKey();

                        long total = mapEntry.getValue().values().stream().mapToLong(x -> x).sum();
                        bugCountMap.put(chargePerson, bugCountMap.getOrDefault(chargePerson, 0L) + total);
                    }
                    // 排序后
                    LinkedHashMap<String, Long> personSortMap = bugCountMap.entrySet().stream()
                            .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
                            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (o, n) -> o, LinkedHashMap::new));

                    LinkedHashMap<String, Map<String, Long>> valueMap = entry.getValue();

                    for (Map.Entry<String, Long> sortEntry : personSortMap.entrySet()) {
                        String personId = sortEntry.getKey();
                        //人名
                        content.append("   >  ").append(USER_MAP.getOrDefault(personId, personId)).append("：");

                        //重新按照状态排序
                        LinkedHashMap<String, Long> linkedHashMap = valueMap.get(personId).entrySet().stream()
                                .sorted(Comparator.comparingInt(stringLongEntry -> STATE_ORDER_LIST.indexOf(stringLongEntry.getKey())))
                                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
                                        (o, n) -> o, LinkedHashMap::new));

                        for (Map.Entry<String, Long> stringLongEntry : linkedHashMap.entrySet()) {
                            content.append(stringLongEntry.getKey()).append(" <font color=\"warning\">**[").append(stringLongEntry.getValue()).append("]**</font>，");
                        }
                        if (content.toString().endsWith("，")) {
                            content = new StringBuilder(content.substring(0, content.length() - 1) + "\n");
                        }
                    }
                    //这个不能少，少了会从上到下全部引用
                    content.append("\n");
                }
            }
            // content.append("[查看缺陷](").append(BUG_URL_MAP.getOrDefault(spaceIdentifier, "https://devops.aliyun.com/projex/project/889ea8b1980f95b17a579997e1/bug#viewIdentifier=1dedc5afd44979211cad516f")).append(")");
            content.append("\n\n\n");
        }
        title.append("**缺陷总计：<font color=\"warning\">[").append(totalBugCount).append("]</font>** \n\n\n");

        long end = System.currentTimeMillis();
        log.info("执行时间：{}毫秒 ", (end - start));

        //关闭后再次调用会报错
        // CLIENT.close();

        if (totalBugCount < 1) {
            title.append("### Good Job\n");
        } else {
            title.append(content);
        }
        title.append("\n <@wjn> <@w> <@liuchen_tqav> <@jianghaipeng_6g1v>  <@lanhuimin_mkfr> <@limengqian_ft2b> <@MaHui> <@所有人> \n请悉知~");
        return title.toString();
    }

    /**
     * 获得工作项的Response
     *
     * @param idList
     * @return
     */
    private List<GetWorkItemInfoResponse> getGetWorkItemInfoResponse(List<String> idList) {
        //根据ID查询详细信息
        List<CompletableFuture<GetWorkItemInfoResponse>> workItemResponseFutureList = Lists.newArrayList();

        for (String id : idList) {
            // Parameter settings for API request
            GetWorkItemInfoRequest getWorkItemInfoRequest = GetWorkItemInfoRequest.builder()
                    .organizationId(ORGANIZATION_ID)
                    .workitemId(id)
                    // Request-level configuration rewrite, can set Http request parameters, etc.
                    // .requestConfiguration(RequestConfiguration.create().setHttpHeaders(new HttpHeaders()))
                    .build();

            // Asynchronously get the return value of the API request
            CompletableFuture<GetWorkItemInfoResponse> responseCompletableFuture = asyncClient.getWorkItemInfo(getWorkItemInfoRequest);
            // 阿里云会限速不能频繁调用
            responseCompletableFuture.join();
            workItemResponseFutureList.add(responseCompletableFuture);
        }

        CompletableFuture<List<GetWorkItemInfoResponse>> workItemResponseList = CompletableFuture.allOf(workItemResponseFutureList.toArray(new CompletableFuture[0]))
                .thenApply(v -> workItemResponseFutureList.stream().map(CompletableFuture::join)
                        .filter(Objects::nonNull)
                        .collect(Collectors.toList()))
                .exceptionally(throwable -> {
                    throwable.printStackTrace();
                    return null;
                });
        return workItemResponseList.join();
    }


    public int getDayThreshold() {
        return dayThreshold.get();
    }

    public void setDayThreshold(int threshold) {
        if (threshold >= 7 && threshold <= 20) {
            dayThreshold.set(threshold);
            log.info("长期未启动的需求报告中阈值设置为：{}", threshold);
            String message = "长期未启动的需求跟踪报告中的时间阈值设置为" + threshold + "天";
            messageSender.sendMessage(message, Env.TEST);
        }
    }

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        // 创建一系列的CompletableFuture，每个都使用apiExecutor线程池
        int count = 5;
        CompletableFuture<?>[] futures = IntStream.range(0, count)
                .mapToObj(i -> CompletableFuture.runAsync(() -> {
                    System.out.println("Task " + i + " started by thread: " + Thread.currentThread().getName());
                    try {
                        // 模拟耗时操作
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                    System.out.println("Task " + i + " finished");
                }, apiExecutor))
                //toArray 是 Stream 接口的一个终止操作，用于将流中的元素收集到一个数组中
                // 方法引用 CompletableFuture[]::new 相当于一个无参构造器，它返回一个 CompletableFuture[] 类型的新数组
                .toArray(CompletableFuture[]::new);

        // 使用CompletableFuture.allOf()来等待所有任务完成
        CompletableFuture.allOf(futures).get(); // 这里会阻塞直到所有任务完成

        // 关闭线程池
        apiExecutor.shutdown();
    }

}
